﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace NumericUpDownForm
{
    public partial class NumericUpDown : UserControl
    {
        Rectangle upButtonRect, downButtonRect;
        Color upBorderColor = Color.FromArgb(160, 160, 160);
        Color downBorderColor = Color.FromArgb(160, 160, 160);
        Color btnArrowColor = Color.Black;
        public int Value
        {
            get { return int.Parse(textBox.Text); }
            set { textBox.Text = value.ToString(); }
        }
        public int Maximum { get; set; }
        public int Minimum { get; set; }
        public Color BaseColor { get; set; }

        public NumericUpDown()
        {
            InitializeComponent();
            Value = 0;
            Maximum = 100;
            Minimum = 0;
            BaseColor = Color.FromArgb(200, 200, 200);
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            upButtonRect = new Rectangle(Width - Padding.Right + 1, 1, Padding.Right - 3, Height / 2 - 1);
            downButtonRect = new Rectangle(Width - Padding.Right+1, Height / 2, Padding.Right - 3, Height / 2 - 1);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.DrawRectangle(new Pen(Color.FromArgb(173, 173, 173)), 0, 1, Width - 2, Height - 2);
            RenderButton(
              e.Graphics,
              upButtonRect,
              BaseColor,
              upBorderColor,
              btnArrowColor,
              ArrowDirection.Up);
            RenderButton(
                e.Graphics,
                downButtonRect,
                BaseColor,
                downBorderColor,
                btnArrowColor,
                ArrowDirection.Down);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (upButtonRect.Contains(e.Location) || downButtonRect.Contains(e.Location))
            {
                BaseColor = Color.FromArgb(180, 200, 250);
            }
            else
            {
                BaseColor = Color.FromArgb(180, 180, 180);
            }
            Invalidate();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            Value += e.Delta / 120;
            if (Value<Minimum)
            {
                Value = Minimum;
            }
            if (Value>Maximum)
            {
                Value = Maximum;
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (upButtonRect.Contains(e.Location) && Value < Maximum)
            {
               upBorderColor = Color.FromArgb(100, 120, 150);
                Value++;
            }
            else if (downButtonRect.Contains(e.Location) && Value > Minimum)
            {
                downBorderColor = Color.FromArgb(100, 120, 150);
                Value--;
            }
            Invalidate();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            upBorderColor = downBorderColor = Color.FromArgb(160, 160, 160);
            Invalidate();
        }

        internal void RenderButton(
           Graphics g,
           Rectangle rect,
           Color baseColor,
           Color borderColor,
           Color arrowColor,
           ArrowDirection direction)
        {
            RenderBackgroundInternal(
                g,
                rect,
                baseColor,
                borderColor,
                0.45f,
                true,
                LinearGradientMode.Vertical);
            using (SolidBrush brush = new SolidBrush(arrowColor))
            {
                RenderArrowInternal(
                    g,
                    rect,
                    direction,
                    brush);
            }
        }

        internal void RenderArrowInternal(
          Graphics g,
          Rectangle dropDownRect,
          ArrowDirection direction,
          Brush brush)
        {
            Point point = new Point(
                dropDownRect.Left + (dropDownRect.Width / 2),
                dropDownRect.Top + (dropDownRect.Height / 2));
            Point[] points = null;
            switch (direction)
            {
                case ArrowDirection.Up:
                    points = new Point[]{
                         new Point (point.X -4,point.Y +2),
                         new Point (point.X ,point.Y -2),
                         new Point (point.X +4,point.Y +2),
                    };
                    break;

                case ArrowDirection.Down:
                    points = new Point[]{
                         new Point (point.X -4,point.Y -2),
                         new Point (point.X ,point.Y +2),
                         new Point (point.X +4,point.Y -2),
                    };
                    break;
            }
            g.DrawLines(new Pen(brush, 2), points);
        }

        internal void RenderBackgroundInternal(
          Graphics g,
          Rectangle rect,
          Color baseColor,
          Color borderColor,
          float basePosition,
          bool drawBorder,
          LinearGradientMode mode)
        {
            using (LinearGradientBrush brush = new LinearGradientBrush(
               rect, Color.Transparent, Color.Transparent, mode))
            {
                Color[] colors = new Color[4];
                colors[0] = GetColor(baseColor, 0, 35, 24, 9);
                colors[1] = GetColor(baseColor, 0, 13, 8, 3);
                colors[2] = baseColor;
                colors[3] = GetColor(baseColor, 0, 68, 69, 54);

                ColorBlend blend = new ColorBlend();
                blend.Positions =
                    new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f };
                blend.Colors = colors;
                brush.InterpolationColors = blend;
                g.FillRectangle(brush, rect);
            }
            if (baseColor.A > 80)
            {
                Rectangle rectTop = rect;
                if (mode == LinearGradientMode.Vertical)
                {
                    rectTop.Height = (int)(rectTop.Height * basePosition);
                }
                else
                {
                    rectTop.Width = (int)(rect.Width * basePosition);
                }
                using (SolidBrush brushAlpha =
                    new SolidBrush(Color.FromArgb(80, 255, 255, 255)))
                {
                    g.FillRectangle(brushAlpha, rectTop);
                }
            }

            if (drawBorder)
            {
                using (Pen pen = new Pen(borderColor))
                {
                    g.DrawRectangle(pen, rect);
                }
            }
        }

        private Color GetColor(Color colorBase, int a, int r, int g, int b)
        {
            int a0 = colorBase.A;
            int r0 = colorBase.R;
            int g0 = colorBase.G;
            int b0 = colorBase.B;

            if (a + a0 > 255)
            {
                a = 255;
            }
            else
            {
                a = Math.Max(a + a0, 0);
            }
            if (r + r0 > 255)
            {
                r = 255;
            }
            else
            {
                r = Math.Max(r + r0, 0);
            }
            if (g + g0 > 255)
            {
                g = 255;
            }
            else
            {
                g = Math.Max(g + g0, 0);
            }
            if (b + b0 > 255)
            {
                b = 255;
            }
            else
            {
                b = Math.Max(b + b0, 0);
            }

            return Color.FromArgb(a, r, g, b);
        }
    }
}
